/*
 * Saphre - Suffix Arrays for Phrase Extraction
 * Copyright (C) 2013 
 * Dale Gerdemann Tübingen, Germany 
 * Niko Schenk Frankfurt am Main, Germany
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package collectors.impl;

import util.sedgewick.StdOut;
import util.Interval;
import collectors.api.PreOrderCollector;
import saphre.core.SuffixArray;
import saphre.core.Store;
import util.tokenization_io.BoundarySymbols;
import collectors.impl.visitors.CollectTraversal;
import util.sorting.EquivalenceRelation;
import util.sorting.Multiset;
import util.sedgewick.UnionFind;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;


/**
 * 
 * @author Dale Gerdemann
 */
public class PreOrderRevExclude implements PreOrderCollector {

    Store store;
    SuffixArray pa;
    double D;
    Interval top;
    int n = 0;
    BoundarySymbols tc;

    /**
     * 
     * @param store
     * @param pa
     * @param top 
     */
    public PreOrderRevExclude(Store store, SuffixArray pa, Interval top) {
        this.store = store;
        this.pa = pa;
        this.top = top;
        tc = store.getTC();
        CollectTraversal.pseudoDepth = 0;

    }

    /**
     * 
     * @param pa 
     */
    public void addPrefixArray(SuffixArray pa) {
    }

    /**
     * 
     * @param inter
     * @param parentLcp
     * @param lcp
     * @param depth
     * @return 
     */
    @Override
    public boolean add(Interval inter, int parentLcp, int lcp,
                       int depth) {
        boolean proceed = true;
        EquivalenceRelation eq = new UnionFind(inter.lb(), inter.rb());
        Multiset leftFreq = new Multiset();
        Multiset rightFreq = new Multiset();
        Map<Integer, Integer> right =
                new TreeMap<Integer, Integer>();
        boolean leftPredIncremented = false;
        int predRightId = -1;
        Map<Integer, Multiset> circumfixes =
                new TreeMap<Integer, Multiset>();

        for (int i = inter.lb(); i < inter.rb(); i++) {
            int loci = pa.getSuftab()[i];

            int rightId = store.text[pa.getSuftab()[i] + 1];

            if (!tc.userSentinel(rightId)) {
                if (right.containsKey(rightId)) {
                    eq.unite(i, right.get(rightId)); // Union-Find
                    rightFreq.incr(rightId);
                }
                else {
                    right.put(rightId, i);
                }
            }

            int leftId = store.text[pa.getSuftab()[i] - lcp];
            if (i != inter.lb() && pa.getLcptab()[i] > lcp) {
                eq.unite(i, i - 1);                  // Union-Find
                if (leftPredIncremented) {
                    leftFreq.incr(leftId);
                    if (!tc.userSentinel(rightId)) {
                        circumfixes.get(leftId).incr(rightId);
                    }
                }
                else {
                    leftFreq.insert(leftId, 2);
                    leftPredIncremented = true;
                    Multiset rightCircum = new Multiset();

                    if (!tc.userSentinel(predRightId)) {
                        rightCircum.incr(predRightId);
                    }
                    if (!tc.userSentinel(rightId)) {
                        rightCircum.incr(rightId);
                    }
                    circumfixes.put(leftId, rightCircum);
                }
            }
            else {
                leftPredIncremented = false;
            }
            predRightId = rightId;
        }
        List<Integer> sing = eq.singletons();
        if (sing.size() > 0) {
            rightFreq.incrAll();
            // leftFreq.incrAll();
            int loc = pa.getSuftab()[inter.lb()];

            // Collect the circumfixes
            StringBuilder circumBuilder = new StringBuilder();
            circumBuilder.append("circum:{");
            for (Map.Entry<Integer, Multiset> e : circumfixes.entrySet()) {
                int leftId = e.getKey();
                List<Integer> numberOccur = new ArrayList<Integer>();
                List<Integer> rightIds =
                        e.getValue().freqGreater(1, numberOccur);
                for (int i = 0; i < rightIds.size(); i++) {
                    if (numberOccur.get(i).intValue() > 1) {
                        int rightId = rightIds.get(i);
                        String rightCircum = store.toString(rightId);
                        String leftCircum = store.toString(leftId);
                        int cnt = numberOccur.get(i);
                        rightFreq.insert(rightId, -cnt);
                        leftFreq.insert(leftId, -cnt);
                        circumBuilder.append("(" + leftCircum + ":" +
                                rightCircum + ":" + cnt + "),");
                    }
                }
            }
            circumBuilder.setCharAt(circumBuilder.length() - 1, '}');
            String circum = circumBuilder.toString() + " ";
            if (circum.length() == 9) {
                circum = "";
            }

            String pref = "suf:" + rightFreq.toStringWF(store) + " ";
            if (pref.length() == 8) {
                pref = "";
            }

            String suff = "pref:" + leftFreq.toStringWF(store) + " ";
            if (suff.length() == 8) {
                suff = "";
            }
            StdOut.print(spaces(2 * depth)
                    + store.toString(loc, loc + lcp) + " "
                    + "tf:" + inter.tf() + " " + " ==> "
                    + pref + suff + circum
                    + "none:" + sing.size());
            System.out.println("\n");
        }
        if (sing.size() > 0) {
            return true;
        }
        else {
            return true;
        }
    }

    /**
     * 
     * @param inter
     * @param lcp
     * @param depth 
     */
    @Override
    public void addTrivial(Interval inter, int lcp, int depth) {
    }

    /*
     * 
     */
    private String spaces(int n) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 2 * n; i++) {
            sb.append(' ');
        }
        return sb.toString();
    }

}
